/***************************************************************************************** 
*                                     TinyRtos51 
*                                The Real-Time Kernel 
*                              Copyright(c) 2024 fanxsp
*                         SPDX-License-Identifier: APACHE-2.0
*       This software is subject to an open source license and is distributed by fanxsp,
*       pursuant to the terms of the Apache License.
******************************************************************************************/
/***************************************************************************************** 
* 				TinyRtos51 OSBinSem.c
* Author: fanxsp 
* Revision: 1.00
* Date: 2023-09-16
* 
******************************************************************************************/
#define __IN_OSBINSEM_C
#include "tinyrtos51.h"

#if OSBINSEMS > 0

/* 每个BinSem占用1 bit */
#if OSBINSEMS%8 > 0
	OStypeInt8u OSLOC_BINSEM OSBinSemArea[OSBINSEMS/8+1] ;
#else
	OStypeInt8u OSLOC_BINSEM OSBinSemArea[OSBINSEMS/8] ;
#endif

/* 位操作掩码  */
OStypeInt8u code OSBinSemMask[]={1,2,4,8,16,32,64,128} ;

/* API */
/******************************************************************************************
* 初始化二进制信号量  在OSStart()前调用
* 参数：eID  二进制信号量ID   state 状态
*******************************************************************************************/
void OSInitBinSem(OStypeInt8u eID,OStypeInt8u state) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSBINSEMS-1) return ;
#endif
	if(state > 0) OSBinSemSet(eID) ;
	else OSBinSemClr(eID) ;
}

/*******************************************************************************************
* 等待二值信号量  在任务中调用 不能在中断中调用
* 参数：eID  二值信号量ID   ticks 超时时间 =0 为永久等待
*******************************************************************************************/
#if OSBYTES_OF_DELAYS > 0
void OSWaitBinSem(OStypeInt8u eID,OStypeOfDelays ticks) 
#else
void OSWaitBinSem(OStypeInt8u eID) 	
#endif
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSBINSEMS-1) return ;
#endif
	OSEnterCritical() ;
#if OSBYTES_OF_DELAYS > 0
	OSTcbArea[OSTaskRunning].timeout = 0 ;
#endif
	if(OSBinSemGet(eID))
	{
		OSBinSemClr(eID) ;
	}
	else
	{
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[OSTaskRunning].delay = ticks ;
#endif
		OSTcbArea[OSTaskRunning].state = OSTCB_WAITING ;
		ACC = eID ;
		_push_(ACC) ;
		OSDelFromList(OSTaskRunning) ;
		_pop_(ACC) ;
		eID = ACC ;
		OSAppendToList(OSHeadBinSem(eID),OSTaskRunning) ;
		OSTaskSw() ;
	}
	OSExitCritical() ;
}

/*******************************************************************************************
* 测试二进制信号量 并清零  可以在中断中调用
* 参数：eID  二进制信号量ID 
* 返回：二进制信号量状态
********************************************************************************************/
OStypeInt8u OSTryBinSem(OStypeInt8u eID) 
{
	OStypeInt8u tmp ;
	
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSBINSEMS-1) return 0 ;
#endif
	OSEnterCritical() ;
	tmp = OSBinSemGet(eID) ;
	OSBinSemClr(eID) ;
	OSExitCritical() ;
	return tmp ;
}

/********************************************************************************************
* 读取二进制信号量 不清零  可以在中断中调用
* 参数：eID  二进制信号量ID 
* 返回：二进制信号量状态
*********************************************************************************************/
OStypeInt8u OSReadBinSem(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSBINSEMS-1) return 0 ;
#endif
	return OSBinSemGet(eID) ;
}

/*********************************************************************************************
* 发送二进制信号量 公共代码 不含临界保护 不能直接调用
* 参数：eID  二进制信号量ID 
*********************************************************************************************/
void OSSignalBinSem(OStypeInt8u eID) 
{
	OStypeInt8u tmp ;

	if(OSHeadBinSem(eID) == OSListArea[OSHeadBinSem(eID)].next)
	{
		OSBinSemSet(eID) ;
	}
	else
	{
		tmp = OSHiPrioInList(OSHeadBinSem(eID)) ;
		OSTcbArea[tmp].state = OSTCB_ELIGIBLE ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[tmp].delay = 0 ;
#endif
//		ACC = tmp ;
//		_push_(ACC) ;
		OSDelFromList(tmp) ;
//		_pop_(ACC) ;
//		tmp = ACC ;
		OSAppendToList(OSHeadEligible,tmp) ;
	}
	return ;
}

/**********************************************************************************************
* 在任务中发送二进制信号量  
* 参数：eID  二进制信号量ID 
***********************************************************************************************/
void OSTaskSignalBinSem(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSBINSEMS-1) return ;
#endif
	OSEnterCritical() ;
	OSSignalBinSem(eID) ;
#if OSMETHOD > 0
	OSTaskSw() ;
#endif
	OSExitCritical() ;
}

/**********************************************************************************************
* 在中断中发送二进制信号量  
* 参数：eID  二进制信号量ID 
**********************************************************************************************/
void OSIntSignalBinSem(OStypeInt8u eID) 
{

#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSBINSEMS-1) return ;
#endif
	OSEnterCritical() ;
	OSSignalBinSem(eID) ;
#if OSMETHOD > 0
	OSPendSVAct() ;
#endif
	OSExitCritical() ;
}

#endif



